package top.healthylife.gateway.platform.baohu.api.secret;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

@Slf4j
public class Core {

	/**
	 * 加密算法RSA
	 */
	public static final String  KEY_ALGORITHM = "RSA";
	/**
	 * 签名算法
	 */
	public static final String  SIGNATURE_ALGORITHM = "SHA1withRSA";

    /**
     * 生成要请求的参数数组
     *
     * @param sParaTemp         请求前的参数数组
     * @return                  要请求的参数数组
     */
    public static Map<String, String> buildRequestPara(Map<String, String> sParaTemp,String signType,String privateKey) throws Exception {
    	// 除去数组中的空值和签名参数
        Map<String, String> sPara = paraFilter(sParaTemp);
        if(StringUtils.isBlank(signType)) {
			return sPara;
		}
        // 生成签名结果
        String mysign = buildRequest(sPara,privateKey);
        // 签名结果与签名方式加入请求提交参数组中
        sPara.put("sign", mysign);
        sPara.put("sign_type", signType);

        return encode(sPara);
    }

	/**
	 * 转码
	 * @param sArray
	 * @return
	 */
	public static Map<String, String> encode(Map<String, String> sArray) {

		Map<String, String> result = new HashMap<String, String>(16);

		if (sArray == null || sArray.size() <= 0) {
			return result;
		}
		String charset = sArray.get("_input_charset");
		for (String key : sArray.keySet()) {
			String value = sArray.get(key);
			if (value != null && !"".equals(value) ) {
				try {
					value = URLEncoder.encode(value, charset);
				} catch (UnsupportedEncodingException e) {
					log.error("UnsupportedEncodingException",e);
				}
			}

			result.put(key, value);
		}

		return result;
	}
	/**
	 * 除去数组中的空值和签名参数
	 *
	 * @param sArray
	 *            签名参数组
	 * @return 去掉空值与签名参数后的新签名参数组
	 */
	public static Map<String, String> paraFilter(Map<String, String> sArray) {

		Map<String, String> result = new HashMap<String, String>(16);

		if (sArray == null || sArray.size() <= 0) {
			return result;
		}

		for (String key : sArray.keySet()) {
			String value = sArray.get(key);
			if (value == null || "".equals(value) || "sign".equalsIgnoreCase(key)
					|| "sign_type".equalsIgnoreCase(key)) {
				continue;
			}
			result.put(key, value);
		}

		return result;
	}

	public static String buildRequest(Map<String, String> sPara,String privateKey) throws Exception {
		// 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		String prestr = createLinkString(sPara, false);
		String sign = sign(prestr, privateKey, "utf-8");
		return sign;
	}
	/**
	 * 签名字符串
	 *
	 * @param text
	 *            需要签名的字符串
	 * @param privateKey 私钥(BASE64编码)
	 *
	 * @param charset
	 *            编码格式
	 * @return 签名结果(BASE64编码)
	 */
	public static String sign(String text, String privateKey, String charset) throws Exception {
		try{
			byte[] privateKeyBytes = Base64.decodeBase64(privateKey);
			String chackPrivateKey = new String(Base64.encodeBase64(privateKeyBytes));

			//校验私钥privateKey位数
			if(!chackPrivateKey.equals(privateKey.replaceAll("[\n\r]*", ""))){
				throw new Exception("密钥位数不对");
			}
			PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
			signature.initSign(privateK);
			signature.update(getContentBytes(text, charset));
			byte[] result = signature.sign();
			return Base64.encodeBase64String(result);
		}catch(java.security.spec.InvalidKeySpecException e){
			throw new Exception("签名失败");
		}

	}


	/**
	 * @param content
	 * @param charset
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private static byte[] getContentBytes(String content, String charset) {
		if (charset == null || "".equals(charset)) {
			return content.getBytes();
		}
		try {
			return content.getBytes(charset);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
		}
	}
	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 *
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @param encode 是否需要urlEncode
	 * @return 拼接后字符串
	 */
	public static String createLinkString(Map<String, String> params, boolean encode) {
		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		StringBuilder prestr = new StringBuilder("");

		String charset = params.get("_input_charset");
		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = params.get(key);
			if (encode) {
				try {
					value = URLEncoder.encode(value, charset);
				} catch (UnsupportedEncodingException e) {
					log.error("UnsupportedEncodingException",e);
				}
			}

			// 拼接时，不包括最后一个&字符
			if (i == keys.size() - 1) {
				prestr.append(key).append("=").append(value);
			} else {
				prestr.append(key).append("=").append(value).append("&");
			}
		}
		return prestr.toString();
	}

}
